package com.liu.webstore.service.impl;

import com.liu.webstore.entity.User;
import com.liu.webstore.enums.StatusEnum;
import com.liu.webstore.service.FollowService;
import com.liu.webstore.service.UserService;
import com.liu.webstore.util.RedisKeyUtil;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @Author LiuYumei
 * @Date 2022/8/6 15:48
 */
@Service
public class FollowServiceImpl implements FollowService {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserService userService;

    /**
     * 关注
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void follow(int userId, int entityType, int entityId) {
        String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
        String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
        redisTemplate.opsForZSet().add(followeeKey, entityId, System.currentTimeMillis());
        redisTemplate.opsForZSet().add(followerKey, userId, System.currentTimeMillis());
    }

    /**
     * 取消关注
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void unFollow(int userId, int entityType, int entityId) {
        String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
        String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
        redisTemplate.opsForZSet().remove(followeeKey, entityId);
        redisTemplate.opsForZSet().remove(followerKey, userId);
    }

    /**
     * 查询关注了多少人
     * @param userId
     * @param entityType
     * @return
     */
    @Override
    public long findFolloweeCount(int userId, int entityType) {
        String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
        return redisTemplate.opsForZSet().zCard(followeeKey);
    }

    /**
     * 查询粉丝的数量
     */
    @Override
    public long findFollowerCount(int entityType, int entityId) {
        String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
        return redisTemplate.opsForZSet().zCard(followerKey);
    }

    /**
     * 是否关注了某人
     */
    @Override
    public boolean hasFollowed(int userId, int entityType, int entityId) {
        // 查看当前用户的关注列表中有没有这个用户
        String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
        return redisTemplate.opsForZSet().score(followeeKey, entityId) != null;
    }

    /**
     * 某用户关注的人的列表
     */
    @Override
    public List<Map<String, Object>> findFolloweeList(int userId, int offset, int limit) {
        String followeeKey = RedisKeyUtil.getFolloweeKey(userId, StatusEnum.ENTITY_TYPE_USER.getStatus());
        // 倒序排序
        Set<Integer> targetIds = redisTemplate.opsForZSet().reverseRange(followeeKey, offset, offset + limit - 1);
        return getMapList(followeeKey, targetIds);
    }

    @Nullable
    private List<Map<String, Object>> getMapList(String followeeKey, Set<Integer> targetIds) {
        if (Objects.isNull(targetIds)) {
            return null;
        }
        List<Map<String, Object>> list = new ArrayList<>();
        targetIds.forEach(targetId -> {
            Map<String, Object> map = new HashMap<>();
            User user = userService.getUserById(targetId);
            map.put("user", user);
            Double score = redisTemplate.opsForZSet().score(followeeKey, targetId);
            assert score != null;
            map.put("followTime", new Date(score.longValue()));
            list.add(map);
        });
        return list;
    }

    /**
     * 关注者列表
     */
    @Override
    public List<Map<String, Object>> findFollowerList(int userId, int offset, int limit) {
        String followerKey = RedisKeyUtil.getFollowerKey(StatusEnum.ENTITY_TYPE_USER.getStatus(), userId);
        Set<Integer> targetIds = redisTemplate.opsForZSet().reverseRange(followerKey, offset, offset + limit - 1);
        return getMapList(followerKey, targetIds);
    }


}
